/**
 * 基础打印语句
 */
void HelloDart() {
  print('Hello Dart');
}

/**
 * 展示基本数据类型操作
 * 
 * 静态强类型：
 * 
 * 
 * 动态推导类型：
 * var 可读可变
 * const/final （常量）可读不可变，const 不可动态初始化
 * dynamic 可变
 */
void BaseVariable() {
  String str = "Hello Dart String";
  print(str); // Hello Dart

  int version = 2;
  double minor = 2.3;

  //--------- 字符串拼接
  print("${str}: $version ($minor) "); //Hello Dart String: 2 (2.3)

  //--------- 类型推导-运行时数据类型
  var vstr = "Hello Dart";
  print(vstr); // Hello Dart
  print(vstr.runtimeType); // 运行时数据类型： String

  //--------- 类型推导-运行时数据类型
  const constr = "Hello";
  final finstr = "Dart";

  print(constr); // HELLO
  print(finstr); // Dart

  // const cnumber = getNumber(); // fail : 不可动态初始化
  final fnumber = getNumber();
  // fnumber = 0;   // fail: 不可变
  print(fnumber); // 1

  // ------ 类型推导-可变值 dynamic
  dynamic temp = "abcde";
  print("$temp --> ${temp.runtimeType}"); // abcde --> String
  temp = 123;
  print("$temp --> ${temp.runtimeType}"); // 123 --> int
}

int getNumber() {
  return 1;
}

/**
 * 展示集合类型操作: 
 * 
 * List/Set/Map
 * 
 */
void ListSetMapVariable() {
// 1. List 类型： [元素1, 元素2, ...]
  List<String> names = ["c", "c++", "java", "typescript", "c"];

  // 一般去重
  List<String> newNames1 = [];
  for (String name in names) {
    // print(name);
    if (!newNames1.contains(name)) {
      newNames1.add(name);
    }
  }

  // 2. Set 类型: [元素1, 元素2, ...]
  // 使用场景：对 List 去重
  Set<int> nums = {1, 2, 3, 4, 1};
  print(nums);

  // Set 对 List 去重
  List<String> newNames2 = List.from(Set.from(names));
  print(newNames2);

  // 3. Map 类型(key/value)
  Map<String, dynamic> info = {
    "name": "why",
    "age": 18,
    "height": 1.88,
  };

  // ------ 集合定义 - 类型推导定义
  var liststr = ['a', 'b', 'c', 'd']; // List<String>
  var listnumber = {1, 2, 3, 4}; // Set<int>
  print(listnumber);
  // ------
}

/**
 * 函数定义
 * 1. 正常函数
 * 2. 必传参数函数
 * 3. 可选传参数函数
 *  3.1 隐式可选参数
 *  3.2 命名可选参数
 */
int FunctionParameter(int v) {
  return v;
}

/**
 * 必传参数函数
 */
void FunctionForceParameter(String name, int age, double height) {
  print("$name $age $height");
}

/**
 * 可选传参数函数 - 隐式可选参数
 */
void FunctionOptionSParameter(String name, [int age = 0, double height = 0]) {
  print("$name $age $height");
}

/**
 * 可选传参数函数 - 位置可选参数
 */
void FunctionOptionTParameter(String name, {int age = 0, double height = 0}) {
  print("$name $age $height");
}

/**
 * 函数第一公民：当作参数
 * 表示可以作为另外一个函数的参数，或另外一个函数的返回值
 */
void ParameterFunc(Function func) {
  func();
}

/**
 * 函数第一公民：当作返回值
 */
Function ReturnFunc() {
  Function temp = HelloDart;
  return temp;
}

/**
 * 匿名函数 - 使用foreach遍历数组
 */
void NoneFuncForeach(List<String> names) {
  // names.forEach((str) {    //
  //   print(str);
  // });
  // names.forEach((str) => print(str));   // 仅单行处理语句可用
  names.forEach(Customeforeach); // 匿名函数调用
}

void Customeforeach(String str) {
  print("--> $str");
}

/**
 * 箭头函数 - 高阶使用
 */
void NoneFuncHightLevel() {
  // 使用 map 遍历处理
  var temp = ["A", "B", "C"].map((item) {
    return item + "a";
  });

  print(temp); // (Aa, Ba, Ca)
  print(temp.runtimeType); // MappedListIterable<String, String>

  temp = List.from(temp); // Iterable --> List
  print(temp); //  [Aa, Ba, Ca]
  print(temp.runtimeType); // List<String>

  // 使用 map 遍历处理 另一种方式
  temp = List.from(["A", "B", "C"].map((item) => item + "b"));
  print(temp); //  [Ab, Bb, Cb]
  print(temp.runtimeType); // List<String>
}

/**
 * 词法作用域
 */
void scapeFunc() {
  var name = "a";
  void foo() {
    var name = "b";
    print(name);
  }
}

/**
 * 词法闭包
 */
void closureFunc() {
  makeAdder(num addBy) {
    return (num i) {
      return i + addBy;
    };
  }

  var adder2 = makeAdder(2);
  print(adder2(10)); // 12
  print(adder2(6)); // 8

  var adder5 = makeAdder(5);
  print(adder5(10)); // 15
  print(adder5(6)); // 11
}

/**
 * 省略返回值函数
 */
normalFunc() {
  foo() {
    return 1;
  }

  too() {
    print('foo function');
  }

  print(foo()); // 1
  print(too()); // null
}

// ------- 运算符
/**
 * 基本 + - * / % 符号
 */
baseOperation() {
  // ---- 除法、整除、取模
  var num = 7;
  print(num / 3); // 除法： 2.33333...
  print(num ~/ 3); // 整除： 2
  print(num % 3); // 取模： 1
}

/**
 * 赋值操作: ??=, ??
 */
valueOperation() {
// ---- 赋值条件运算符 ??=
  var name = 'wife';
  print(name); // wife

  var name_copy = null;
  name_copy ??= 'james';
  print(name_copy); // james, 当 name_copy 为 null 的时候才赋值 james

  // ---- 赋值条件运算符 ??
  var temp = null;
  temp = "why";
  temp = null ?? 'not values';
  print(temp); // why, 当 temp 有值的时候 赋值给 name
  print(temp); // not values, 当 none 无值的时候 赋值 'not values' 给 name
}

/**
 * 
 */
class Person {
  String name = "";

  void run() {
    print("$name is running");
  }

  void eat() {
    print("$name is eating");
  }

  void stop() {
    print("$name is stop");
  }
}

/**
 * 级联操作
 */
cascadeOperation() {
  // 普通操作
  final p = Person();
  p.name = "zinface"; // 初始化变量赋值
  p.run(); //调用 run 函数
  p.eat(); //调用 eat 函数
  p.stop(); //调用 stop 函数

  // 级联操作
  final p1 = Person() // .. 级联操作一步完成
    ..name = "cascade"
    ..run()
    ..eat()
    ..stop();
}

/**
 * 流程控制 - if else, for, for in, switch
 */
baseProcessControl() {
  var name = null;

  if (name == null) {
    name = ['c', 'c++', 'java', 'python', 'golang', 'dart'];
  }

  List<String> names = List.from(name);

  // for - 基本循环
  for (var i = 0; i < names.length; i++) {
    print("-> ${names[i]}");
  }
  // for in - 遍历 List/Set
  for (var item in names) {
    print("--> $item");

    switch (item) {
      case 'c':
        print('$item - 推荐学习 《C语言程序设计》');
        break;
      case 'c++':
        print('$item - 推荐学习 《c++ Prime Plus》');
        break;
      case 'golang':
        print('$item - 学习deepin后端');
        break;
    }
  }
}

/**
 * 类和对象
 * 1. 类的声明
 * 2. 类的构造函数
 *  2.1 普通写法
 *  2.2 语法糖写法
 *  2.3 命名构造写法
 *  2.4 初始化列表写法
 *  2.5 工厂构造写法
 */
class Student {
  String name = "";
  int age = 0;

// 无构造函数

  void eating() {
    print("$name 在吃.");
  }
}

/**
 * Teacher 类相关
 * 1. 类构造函数基本写法
 */
class Teacher {
  String name = "";
  int age = 0;

// ---- 普通写法
  // 必选参数，可选参数
  // Teacher(String name, int age, [int height = 0]) {
  //   this.name = name;
  //   this.age = age;
  // }
// ---- 语法糖写法
  Teacher(this.name, this.age, [int heigth = 0]) {}

// ---- 命名构造写法
  Teacher.fromMap(Map<String, dynamic> map) {
    this.name = map["name"];
    this.age = map["age"];
  }

  void eating() {
    print("$name 在吃东西.");
  }
}

/**
 * Rectangle 类相关
 * 1. 初始化列表构建函数
 */
class Rectangle {
  int a = 0;
  int b = 0;
  int c = 0;

  String name;

// 普通写法
  // Rectangle(this.a, this.b) {
  //   this.c = a * b;
  // }
// 初始化列表
  // Rectangle(this.a, this.b) : c = a * b, name = "fuck";

  Rectangle(this.name, this.a, this.b);
  Rectangle.fromName(String name) : this(name, 0, 0); // 重定向

  // 重写 toString 以便 print 打印
  @override
  String toString() {
    return "a=${this.a}, b=${this.b}, c=${this.c}";
  }
}

/**
 * ConClass 类相关
 * 1. 常量构造函数
 */
class ConClass {
  final String name;

  const ConClass(this.name);
}

/**
 * FactoryClass 类相关
 * 1. 工厂构造函数
 */
class FactoryClass {
  String name;

  static final Map<String, FactoryClass> _cache = <String, FactoryClass>{};

  factory FactoryClass(String name) {
    if (_cache.containsKey(name)) {
      FactoryClass f = _cache[name] ?? FactoryClass._internal(name);
      return f;
    } else {
      final f = FactoryClass._internal(name);
      _cache[name] = f;
      return f;
    }
  }

  FactoryClass._internal(this.name);
}

/**
 * Dog 类 - getter/setter 操作
 */
class Dog {
  String _name;

  String get name => _name;

  set name(String name) {
    _name = name;
  }

  Dog(this._name);
}

/**
 *  Parent 类 - 继承操作
 */

class Parent {
  String eat = "";

  void eating() {
    print("吃$eat");
  }

  Parent(this.eat);
}

class Child extends Parent {
  String name = "";

  @override
  void eating() {
    print("$name在吃$eat");
  }

  Child(this.name, String eat) : super(eat);
}

/**
 * Simple 类 - 抽象类
 * 1. 抽象类无法被实例化 - Abstract classes can't be instantiated.
 * 2. 抽象类中可定义抽象方法 - 有定义无实现
 */
abstract class Simple {
  getAreal();
}

class SimpleClass extends Simple {
  double r;
  SimpleClass(this.r);

  @override
  getAreal() {
    return r * r * 3.14;
  }
}

SumSimple(Simple s) {
  return s.getAreal();
}

absclassFunc() {
  Simple s = SimpleClass(10);
  print(SumSimple(s));
}

/**
 * Runnner 类 - 隐式接口(abstract class, implements)
 * 1. Dart 中的接口比较特殊，没有一个专门的关键字来声明接口
 *  默认情况下，定义的每个类相当于默认声明了一个接口，可以 由其他的类来实现（Dart不支持多继承)
 */
abstract class Runnner {
  run();
}

abstract class Flyer {
  fly();
}

class SuperMan implements Runnner, Flyer {
  @override
  run() {
    print("超人在跑");
  }

  @override
  fly() {
    print("超人在飞");
  }
}

/**
 * Mixin 混入概念
 */
mixin Run {
  run() {
    print("Run!");
  }
}
mixin Go {
  go() {
    print("go!");
  }
}

class Ready with Run, Go {}

classFunc() {
  // -------------- Student ----------------
  // 创建 Student 类的实例
  var s = new Student();
  var s1 = Student(); // Dart 2.0 时不需要 new

  s.name = "zinface"; // 无构造函数

  // -------------- Teacher ----------------

  // 使用类构造函数 创建 Teacher 类的实例
  var t = new Teacher("zinface", 22, 10);
  t.eating();

  // Key\Value 映射
  Map<String, dynamic> info = {"name": "kobe", "age": 30, "height": 40};

  final mapT = Teacher.fromMap(info);
  mapT.eating();

  // -------------- Rectangle ----------------
  final r1 = Rectangle("zinface", 2, 3);
  print(r1);

  final ra = Rectangle.fromName("zinface");
  final rb = Rectangle.fromName("zinface");
  // 判断两个实例是否相同
  print(identical(ra, rb)); // false

  // -------------- ConClass ----------------
  var c1 = ConClass("zinface");
  var c2 = ConClass("zinface");
  // 判断两个实例是否相同
  print(identical(c1, c2)); // false

  // 使用 const 接收为同一个实例
  const c3 = ConClass("zinface");
  const c4 = ConClass("zinface");
  print(identical(c3, c4)); // true

  // -------------- Dog ----------------
  final d1 = Dog("c");
  d1.name = "cat";
  print(d1.name);

  // -------------- Child ----------------
  var child1 = Child("zinface", "西瓜");
  // child1.name = "zinface";
  child1.eating();

  // -------------- Simple ----------------
  absclassFunc();

  // -------------- SuperMan ----------------
  SuperMan()
    ..run()
    ..fly();
}

/**
 * 泛型 类定义
 */
class Location<T> {
  T x;
  T y;

  Location(this.x, this.y);
}

/**
 * 泛型 方法
 */
T getFirst<T>(List<T> list) {
  return list[0];
}

anyTypeFun() {
  // --------- List ---------
  var listvals = ["why", "who", "what", 111];
  print(listvals.runtimeType); // List<Object>

  // 限制类型
  // var listFixed = <String>["why", "who", "what", 111]; // 最后一个报错
  // List<String> liststrs = ["why", "who", "what", 111]; // 最后一个报错

  // --------- Map ---------
  var mapvals = {"name": "why", "age": 111, 0: 0};
  print(mapvals.runtimeType); // _InternalLinkedHashMap<Object, Object>

  // 限制类型
  // var infos = <String, String>{"name": "zinface", "age": 18}; // 18 不能放里面
  // Map<String, String> infos = {"name": "zinface", "age": 18}; // 18 不能放里面

  // --------- Location ---------
  Location l1 = Location<String>("a", "b");

  // --------- getFirst ---------
  List<int> nums = [1, 2, 3, 4];
  print(getFirst(nums)); // 1

  List<String> names = ["name", "why", "age"];
  print(getFirst(names)); // name
}

/**
 * Dart 库导入
 * 1. dart中任何一个dart文件都是一个库，即使没有用关键字 library 声明
 *  库的使用使代码的重用性得到提高，并且更好的组合代码，导入一个库来使用它所提供的功能。
 * 2. 库导入
 *  2.1 import 'uri';
 *  2.2 import 'dart:io';  // dart 前缀表示Dart的标准库，如dart:io、dart:html、dart:math, dart:core(可省略)
 *  2.3 import 'lib/super/super.dart';  // 使用相对路径导入库，为引入自己项目中定义的其他dart文件
 * 3. Pub包管理工具管理的库 - 可使用第三方库 -- 公共仓库
 *  3.1 import 'package:flutter/material.dart';
 * 4. 指定库内容: show/hide
 *  4.1 import 'lib/super/super.dart' show Man, Utils;
 *  4.2 import 'lib/super/super.dart' hide Man;
 * 5. 库内容与当前文件内容冲突
 *  5.1 import 'lib/super/super.dart' as su;
 */
libFun() {}

/**
 * Dart 库定义
 * 1. dart中定义库时，可以使用library关键字给库命名
 *  1.1 library math; // 目前来说 library 并不影响导入 uri，
 *  
 */

/**
 * Dart 庞大文件拆分: part or export
 * 1. dart 中一个库过大时，将所有内容保存到一个地方并不合理，可以使用 part 关键字进行管理(官方已经不建议使用part了) 
 *  1.1 Super.dart 与 Man.dart
 *    使用 SuperMan.dart 中 编写:
 *      export 'Super.dart'
 *      export 'Man.dart'
 */

// main函数入口
void main(List<String> args) {
  // 基本认识 - 函数调用
  HelloDart();
  // 基本数据类型
  BaseVariable();
  // 集合数据类型
  ListSetMapVariable();

  // 函数参数 - 普通函数
  int v = FunctionParameter(5);
  // 函数参数 - 必传
  FunctionForceParameter("zinface", 18, 1.75);
  // 函数参数 - 可选传 - 隐式可选
  FunctionOptionSParameter("zinface", 18);
  // 函数参数 - 可选传 - 位置可选
  FunctionOptionTParameter("zinface", age: 18, height: 1.75);

  // 函数第一公民：当作参数
  ParameterFunc(HelloDart);
  // 函数第一公民：当作返回值
  ReturnFunc()();

  // 匿名函数 - 使用foreach遍历数组
  NoneFuncForeach(["A", "B", "C"]);

  // 箭头函数 - 高阶使用
  NoneFuncHightLevel();

  // 词法作用域
  scapeFunc();

  // 词法闭包
  closureFunc();

  // 函数返回值 - 省略
  normalFunc();

  // ---------- 运算符
  // 运算符 - 基本 +-*/% 符号
  baseOperation();
  // 运算符 - 赋值运算符: ??, ??=
  valueOperation();
  // 运算符 - 级联操作 ..
  cascadeOperation();

  // --------- 流程控制
  // 流程控制 if else, for, for in, switch
  baseProcessControl();

  // 类和对像
  classFunc();

  // 泛型
  anyTypeFun();

  // dart 库使用：导入/定义/拆分
  libFun();

  // other
  Other();
}

/**
 * dynamic 与 Object 的区别：
 * 1. dart 所有的类默认都继承 Object
 */
Other() {
  String s1 = "yes";
  print(s1.length); // 3

  Object s2 = "yes";
  // print(s2.length); // Object 无length方法

  dynamic s3 = "yes";
  print(s3.length); // 3

  Map<String, Object> map1 = {"name": "why", "age": 18, "height": 1.88};
  Map<String, dynamic> map2 = {"name": "why", "age": 18, "height": 1.88};

  // print(map1["name"].length); 无法使用 length
  print(map2["name"].length);
}
